package org.examcity.domain.fixtures;

import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;

/**
 * Support methods to create fixtures.
 * 
 * @author Antonio Gomes
 */
public final class FixtureUtil {

	private static ApplicationContext applicationContext;

	private FixtureUtil() {
		// no instance allowed
	}

	/**
	 * Sets the current application context to be shared by all tests.
	 * @param applicationContext
	 */
	public static void setApplicationContext(ApplicationContext applicationContext) {
		FixtureUtil.applicationContext = applicationContext;
	}

	/**
	 * Gets the current application context shared by all tests.
	 * @return context
	 */
	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	/**
	 * Convenience method that creates an instance of class using standard reflection and wraps all
	 * checked exception with an unchecked exception {@link FixtureException}.
	 * @param <T>
	 * @param clazz
	 * @return newly create instance
	 */
	public static <T> T newInstance(Class<T> clazz) {
		try {
			return clazz.newInstance();
		} catch (InstantiationException e) {
			throw new FixtureException(e);
		} catch (IllegalAccessException e) {
			throw new FixtureException(e);
		}
	}

	/**
	 * Convenience method that creates an instance of a clazz either via the current
	 * {@link ApplicationContext} or via the method {@link Class#newInstance()} (if no bean from the
	 * given class is defined in the context).
	 * <p>
	 * This method is supposed to be used with prototype scoped beans and requires the method
	 * application context to be set via {@link #setApplicationContext(ApplicationContext)}
	 * @param <T>
	 * @param clazz
	 * @return newly created instance
	 */
	@SuppressWarnings("unchecked")
	public static <T> T create(Class<T> clazz) {
		Assert.notNull(applicationContext, "ApplicationContext not set");
		String[] names = applicationContext.getBeanNamesForType(clazz);
		if (names.length == 1) {
			// ok, bean definition found
			return (T) applicationContext.getBean(names[0]);
		} else if (names.length == 0) {
			// bean not defined in spring... fallback to Class.newInstance()
			return FixtureUtil.newInstance(clazz);
		}
		throw new FixtureException("Found more than one definition for " + clazz
				+ " found in context");
	}

	public static boolean isEquals(Object v1, Object v2) {
		if (v1 == null) {
			return v2 == null;
		} else if (v2 == null) {
			return false;
		}
		return v1.equals(v2);
	}

}
